/*
 * Copyright 2002-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.transaction.config;

import org.w3c.dom.Element;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * {@code NamespaceHandler} allowing for the configuration of
 * declarative transaction management using either XML or using annotations.
 *
 * <p>This namespace handler is the central piece of functionality in the
 * Spring transaction management facilities and offers two approaches
 * to declaratively manage transactions.
 *
 * <p>One approach uses transaction semantics defined in XML using the
 * {@code <tx:advice>} elements, the other uses annotations
 * in combination with the {@code <tx:annotation-driven>} element.
 * Both approached are detailed to great extent in the Spring reference manual.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @since 2.0
 */
public class TxNamespaceHandler extends NamespaceHandlerSupport {

	static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";

	static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";


	static String getTransactionManagerName(Element element) {
		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
	}

	/*
	 * @Transactional的总结：
	 * Spring使用AOP实现事务的统一管理，为开发者提供了很大的便利。但是，有部分开发人员会误用这个便利，基本都是下面这两种情况：
	 * 1.A类a1方法里面调用a2方法，A类的a1方法没有标注@Transactional，a2方法标注@Transactional；
	 * 2.将@Transactional注解标注在非public方法上。
	 *
	 * 第一种为什么是错误用法，原因很简单，a1方法是目标类A的原生方法，调用a1的时候即直接进入目标类A进行调用，
	 * 在目标类A里面只有a2的原生方法，在a1里调用a2，即直接执行a2的原生方法，并不通过创建代理对象进行调用，
	 * 所以并不会进入TransactionInterceptor的invoke方法，不会开启事务。
	 *
	 * @Transactional的工作机制是基于AOP实现的，而AOP是使用动态代理实现的，动态代理要么是JDK方式、要么是Cglib方式。
	 * 如果是JDK动态代理的方式，根据上面的分析可以知道，目标类的目标方法是在接口中定义的，也就是必须是public修饰的方法才可以被代理。
	 * 如果是Cglib方式，代理类是目标类的子类，理论上可以代理public和protected方法，但是Spring在进行事务增强是否能够应用到当前目标类判断的时候，
	 * 遍历的是目标类的public方法，所以Cglib方式也只对public方法有效。
	 *
	 * 深入Class类getMethods方法，可以看到取得是public修饰的方法。
	 */
	// 学习网址
	// https://juejin.im/post/59e87b166fb9a045030f32ed    这篇文章写的比较好，容易理解
	// https://www.cnblogs.com/youzhibing/p/6690341.html   深入理解Spring事务中的ThreadLocal
	// https://blog.csdn.net/lz710117239/article/details/78787280
	// https://blog.csdn.net/lyc_liyanchao/article/details/85136453
	@Override
	public void init() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		// 注册AnnotationDrivenBeanDefinitionParser
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}

}
